/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ServerImp;

import Shared.*;
import Shared.User;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author belal
 */

public class serverImp extends UnicastRemoteObject implements ServerInt {

    DatabaseConnection dbConn;
    private static HashMap<String, ClientInt> clientsMap = new HashMap<>();
    private static HashMap<String,ClientInt> chatMap = new HashMap<>();
    User user;
    //private static int identifier=0;
    private String identifier;
    private Registry reg=null;
    private static int onUsers=0;
    private static int offUsers=0;
    ServerStart server;
    ClientInt clientInt;
    public serverImp(ServerStart server) throws RemoteException {
        try {
            //System.out.println("kkk");
            reg = LocateRegistry.createRegistry(5005);
            reg.rebind("ChattingService", this);
            this.server=server;
            dbConn = new DatabaseConnection();
            offUsers=dbConn.getUserCount();
            //System.out.println(offUsers);
           updateOnlineUsers(onUsers,offUsers,server);
        } catch (RemoteException ex) {
            System.out.println("Server already run");
            //System.exit(0);
        }
    }
    public void shutDown() throws RemoteException{
        for (Map.Entry<String, ClientInt> entry : clientsMap.entrySet()) {
           entry.getValue().stopServer("Sever is Forced Shutdown");
	}
        UnicastRemoteObject.unexportObject(reg, true);
    }
    @Override
    public ArrayList<User> loginUser(User user, ClientInt cl) throws RemoteException {
        System.out.println("login in serverimp");
        ArrayList<User> friendList = new ArrayList<>();
        int returnVal = dbConn.loginUser(user);
        if (returnVal == 1) {
            System.out.println("My Mail:"+user.getUserMail());
            clientsMap.put(user.getUserMail(), cl);
            updateOnlineUsers(clientsMap.size(),(offUsers-(clientsMap.size())),server);
            friendList = checkStatus(dbConn.getUserFreinds(user.getUserMail()));
        }
         for (Map.Entry<String, ClientInt> entry : clientsMap.entrySet()) {
             System.out.println(entry.getValue().toString());
	}
        return friendList;
    }
    public ArrayList<User> checkStatus(ArrayList<User> friends) {
        for (int i = 0; i < friends.size(); i++) {
            if (clientsMap.containsKey(friends.get(i).getUserMail())) {
                friends.get(i).setStatus(1);
            }
        }
        return friends;
    }
    @Override
     public void informStatus(ArrayList<User> friends)throws RemoteException{
        for (int i = 0; i < friends.size(); i++) {
            if (clientsMap.containsKey(friends.get(i).getUserMail())) {
                ClientInt cli=clientsMap.get(friends.get(i).getUserMail());
                cli.updateFriendList();   
            }
        }
    }
    @Override
    public void changeStatus(String mail, int status) throws RemoteException {
        ArrayList<User> frList=null;  
        dbConn.changeStatus(mail, status);
        frList=dbConn.getUserFreinds(mail);
        informStatus(frList);
        
        
        
    }
     @Override
    public ArrayList<User> getFriendList(String mail) throws RemoteException {
       return dbConn.getUserFreinds(mail);
    }


    @Override
    public int registerUser(User user) throws RemoteException {
        return dbConn.registerUser(user);
    }
    

    @Override
    public int addFreind(User sender, String reciever) throws RemoteException {
        int returnVal = 0;
        boolean exist = clientsMap.containsKey(reciever);
        if (exist){
            ClientInt cliReciever= clientsMap.get(reciever);
            int res=cliReciever.getFriendRequestNotify(sender);
            if (res>=1) {
                dbConn.updateFriendRequest(sender.getUserMail(), reciever); 
                cliReciever.updateFriendList();
                returnVal=1;
            }
        } else {
             dbConn.addFreindOffline(sender.getUserMail(), reciever);
            // returnVal=2;
        }
        return returnVal;
    }

    @Override
   //get remote object of my friend to p2p chat
    public ClientInt chatFreind(String mail) throws RemoteException {

        ClientInt cli = null;
        if (clientsMap.containsKey(mail)) {
            cli = clientsMap.get(mail);
        } else {
            System.out.println("doesn't exist");
        }
        return cli;

    }
    
    @Override
    public int checkMail(String mail) throws RemoteException {
        int cMail = 0;
        try {
            cMail = dbConn.userMail(mail);
        } catch (RemoteException ex) {
            
        }
        return cMail;
    }
    @Override
    public String checkPass(String mail, String pass) throws RemoteException {
        String cPass = new String();
        try {
            // to Check mail of sign up exist or not. return 1 if doesn't exist
            cPass = dbConn.userPass(mail, pass);
        } catch (RemoteException ex) {
            Logger.getLogger(serverImp.class.getName()).log(Level.SEVERE, null, ex);
        }
        return cPass;
    }
    @Override
    public void signOut(String mail) throws RemoteException {
     
        if (clientsMap.containsKey(mail)) {
            clientsMap.remove(mail);
            dbConn.changeStatus(mail,4);
        } else {
            System.out.println("no clients");
        }
         for (Map.Entry<String, ClientInt> entry : clientsMap.entrySet()) {
             entry.getValue().notifyMyFriend(mail, "Logout"); 
	}   
    }
    @Override
    public ArrayList<ClientInt> StartChatGroup(ArrayList<String> mails) throws RemoteException {
        ArrayList<ClientInt> clients=new ArrayList<>();
        for(String mail : mails) {
            if (clientsMap.containsKey(mail)) {
                clients.add(clientsMap.get(mail));
                System.out.println("mails:"+mail);
            }
        }
        return clients;
    }
    @Override
    public String getIdentifier() throws RemoteException{
        return identifier;
    }
    @Override
    public void setIdentifier() throws RemoteException {
        Date date = new Date();
        identifier = date.toString();
        System.out.println("identifier of server:"+identifier);
    }

    @Override
    public ArrayList<ClientInt> getMyFriends(ArrayList<String> mails) throws RemoteException{
        ArrayList<ClientInt> myFreinds=new ArrayList<>();
        for(String mail : mails) {
            if (clientsMap.containsKey(mail)) {
                myFreinds.add(clientsMap.get(mail));
            }
        }
        return myFreinds;
    }

    @Override
    public void publishMessage(String msg) throws RemoteException {
       for (Map.Entry<String, ClientInt> entry : clientsMap.entrySet()) {
           entry.getValue().notifyFromServer(msg);
	}
 
    }
    @Override
    public int getUserCount()throws RemoteException{
        return dbConn.getUserCount();
    }
    
    public void updateOnlineUsers(int onUser,int offUser,ServerStart server){
       server.updateOnlineUsers(onUser,offUser);
       
    }
    
    @Override
    public ArrayList<User> CheckFriendRequests(String mail)throws RemoteException{
        return dbConn.getFriendRequest(mail);
       
    }
    @Override
    public ArrayList<User> updateFriendRequest(String sender, String reciever) throws RemoteException {
         return dbConn.updateFriendRequests(sender, reciever);
    }

    @Override
    public void startConversation(String[] freindsMail) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public boolean attachFile() throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public boolean deleteContact(String mail) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void saveChat(String text) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public boolean sendMail(String fromMail, String toMail) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public int countOnlineUsers() throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void printName(String user) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

   
    @Override
    public ArrayList<String> getAllMail() throws RemoteException {
        ArrayList<String> mails = new ArrayList<>();
        mails = dbConn.getAllMail();
        return mails;
    }

}
